--[[
	gSpeak
	Author: Adult
]]--

local data = "gspeak/data.txt"
local voice = {}

-- Load the file 
local function loadFile()
	if not file.Exists( data, "DATA" ) then
		return false, data .. " does not exist"
	end
	
	voice = util.JSONToTable( file.Read( data, "DATA" ) )
	
	voice = voice or {}
	return true 
end

-- Save the file
local function saveFile()
	file.Write( data, util.TableToJSON( voice ) )
	return true 
end

-- Setting up channels
local function setupChannel( id, admin, private )
	-- Don't want to use an invalid player
	if not isValidPlayer( admin ) then
		return false, "Admin not valid"
	end

	-- Don't overwrite channels
	if not channelExists( id ) then
		return false, "Channel exists"
	end

	-- Channel table
	voice.channels[id] = {}

	local channel = voice.channels[id]

	channel.admin   = { admin:SteamID() }
	channel.members = { admin:SteamID() }
	channel.banned  = {}
	channel.private = tobool( private )
	broadcastVoiceData()

	saveFile()
end

local function removeChannel( id )
	if not channelExists( id ) then
		return false, "Channel does not exist"
	end

	table.Empty( voice.channels[id] )
	saveFile()

	return true
end

-- Add user to channel
local function addToChannel( id, ply )

-- Remove user from channel
local function kickFromChannel( id, ply )
	if not isValidPlayer( ply ) then
		return false, "Player not valid"
	end

	if not channelExists( id ) then
		return false, "Channel not valid"
	end

	local m = voice.channels[id].members

	for k,v in pairs( player.GetAll() ) do 
		if table.HasValue( m, v:SteamID() ) then
			table.remove( m, k )
			sendMessage( v, "You have been kicked from the channel.", false )
		end
	end

	saveFile()
	return true
end

-- Ban user from channels
local function banFromChannel( id, ply )
	if not isValidPlayer( ply ) then
		return false, "Player not valid"
	end

	if voice.channels[id] ~= nil then
		return false, "Channel not valid"
	end

	if ply:isBannedFromChannel( id ) then
		return false, "Player already banned"
	end

	if ply:isInChannel( id ) then
		kickFromChannel( id, ply )
	end

	table.insert( voice.channels[id].banned, ply:SteamID() )
	saveFile()

	return true
end

-- Messages
local function sendMessage( ply, msg, usederma )
	local data = {}
	data.usederma = usederma 
	data.msg = msg 

	net.Start( VOICE_MESSAGE )
		net.WriteTable( data )
	net.Send( ply )
end


-- send voice data
local function broadcastVoiceData()
	local data = {}
	local data.channels = {}

	for k,v in pairs( voice.channels ) do
		if not v.private then
			table.insert( data.channels, v )
		end
	end

	net.Start( VOICE_DATA )
		net.WriteTable( data )
	net.Broadcast()
end

-- Send voice data to one player
local function sendVoiceData( ply )
	local data = {}
	local data.channels = {}

	for k,v in pairs( voice.channels ) do
		if not v.private and not ply:isGAdmin() then
			table.insert( data.channels, v )
		end
	end

	net.Start( VOICE_DATA )
		net.WriteTable( voice )
	net.Send( ply )
end

--[[
	Net Handlers
]]--

-- Request Join 
net.Receive( VOICE_REQJOIN, function( _, sender )
	local id = net.ReadString() 

	if not channelExists( id ) then
		sendMessage( sender, "Channel does not exist.", true )
		return 
	end

	if sender:isInChannel( id ) then
		sendMessage( sender, "Player already in channel.", true )
		return 
	end

	if sender:isBannedFromChannel( id ) then 
		sendMessage( sender, "Player is banned from channel.", true )
		return 
	end

	if voice.channels[id].private then 
		sendMessage( sender, "Channels is private. Please have the channel admin add you manually.", true )
		return 
	end


end)

-- Request data 
net.Receive( VOICE_REQDATA, function( _, sender ) 
	sendVoiceData( sender )
end) 

--[[
	ConCommands
	SuperAdmin only.
	These do not add specific people to channel admins, rather server admins.
]]--

-- gspeak_admin_add "STEAM_0:0:0"
local function addGAdmin( ply, cmd, args )
	if not ply:IsSuperAdmin() then
		sendMessage( ply, "You don't have access to this command.", true )
		return 
	end

	table.insert( voice.admins, args[1] )
	sendMessage( ply, args[1] .. " added as an admin.", true )
end

concommand.Add( "gspeak_admin_add", addGAdmin )

-- gspeak_admin_remove "STEAM_0:0:0"
local function removeGAdmin( ply, cmd, args )
	if not ply:IsSuperAdmin() then
		sendMessage( ply, "You don't have access to this command.", true )
		return 
	end

	if not table.HasValue( voice.admins, args[1] ) then
		sendMessage( ply, "User is not an admin.", true )
		return 
	end

	table.RemoveByValue( voice.admins, args[1] )
	sendMessage( ply, args[1] .. " is no longer an admin.", true )
end

concommand.Add( "gspeak_admin_remove", removeGAdmin )

--[[
	Hooks
]]--

local function init()
	-- Initial File structure setup
	if not file.IsDir( "gspeak", "DATA" ) then
		file.CreateDir( "gspeak" )
		file.Write( data, "" )
	end

	loadFile()
end

hook.Add( "Initialize", "GSpeak_init", init )


local function initialSpawn( ply )
	sendVoiceData( ply )
end

hook.Add( "PlayerInitialSpawn", "GSpeak_initspawn", initialSpawn )